#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
3761协议报文解析器
基于QGDW1376.1规约实现
"""

import struct
from typing import Dict, List, Any, Optional, Tuple
from datetime import datetime


class Frame3761Parser:
    """3761协议帧解析器"""
    
    def __init__(self):
        self.AFN_NAMES = {
            0x00: "确认/否认",
            0x01: "复位命令", 
            0x02: "链路接口检测",
            0x04: "设置参数",
            0x09: "请求终端配置及信息",
            0x10: "数据转发"
        }
        
    def parse_frame(self, data: str) -> Dict[str, Any]:
        """
        解析3761协议帧
        
        Args:
            data: 十六进制字符串，如 "68 42 01 42 01 68 CA..."
            
        Returns:
            解析结果字典
        """
        # 清理并转换数据
        hex_data = data.replace(' ', '').replace('\n', '').replace('\r', '')
        if len(hex_data) % 2 != 0:
            raise ValueError("十六进制数据长度必须为偶数")
            
        # 转换为字节数组
        byte_data = bytes.fromhex(hex_data)
        
        result = {
            'raw_data': hex_data,
            'frame_length': len(byte_data),
            'parse_success': False,
            'error': None
        }
        
        try:
            # 验证最小帧长度
            if len(byte_data) < 12:  # 最小帧长度
                raise ValueError(f"帧长度太短: {len(byte_data)} < 12")
                
            # 解析帧结构
            self._parse_frame_structure(byte_data, result)
            result['parse_success'] = True
            
        except Exception as e:
            result['error'] = str(e)
            
        return result
    
    def _parse_frame_structure(self, data: bytes, result: Dict[str, Any]):
        """解析帧结构"""
        pos = 0
        
        # 1. 检查起始字符
        if data[pos] != 0x68:
            raise ValueError(f"起始字符错误: 0x{data[pos]:02X}, 期望: 0x68")
        result['start_char'] = f"0x{data[pos]:02X}"
        pos += 1
        
        # 2. 解析长度域L (2字节, 小端序)
        length_bytes = data[pos:pos+2]
        length = struct.unpack('<H', length_bytes)[0]  # 小端序
        # 实际用户数据长度 = 报文总长度 - 固定头部长度
        actual_user_data_length = len(data) - 12  # 68 L L 68 C A(5) CS 16 = 12字节固定开销
        result['length_field'] = {
            'raw': [f"0x{b:02X}" for b in length_bytes],
            'declared_length': length,
            'actual_frame_length': len(data),
            'calculated_user_data_length': actual_user_data_length,
            'description': f"声明长度: {length} 字节, 实际帧长: {len(data)} 字节"
        }
        pos += 2
        
        # 3. 再次检查长度域L (重复)
        length_bytes2 = data[pos:pos+2] 
        if length_bytes != length_bytes2:
            raise ValueError("两个长度域不匹配")
        pos += 2
        
        # 4. 检查第二个起始字符
        if data[pos] != 0x68:
            raise ValueError(f"第二个起始字符错误: 0x{data[pos]:02X}")
        result['start_char2'] = f"0x{data[pos]:02X}"
        pos += 1
        
        # 5. 解析控制域C
        control = data[pos]
        result['control_field'] = self._parse_control_field(control)
        pos += 1
        
        # 6. 解析地址域A (5字节)
        address_bytes = data[pos:pos+5]
        result['address_field'] = self._parse_address_field(address_bytes)
        pos += 5
        
        # 7. 解析应用层数据
        # 应用层数据长度 = 总长度 - 固定头部 - 校验码 - 结束符
        # 固定头部：68(1) + L(2) + L(2) + 68(1) + C(1) + A(5) = 12字节
        app_data_length = len(data) - 12 - 1 - 1  # 减去头部、校验码、结束符
        
        if app_data_length <= 0:
            raise ValueError("应用层数据长度计算错误")
            
        app_data = data[pos:pos+app_data_length]
        result['application_data'] = self._parse_application_layer(app_data)
        pos += app_data_length
        
        # 8. 解析校验码
        checksum = data[pos]
        calculated_cs = self._calculate_checksum(data[0:pos])
        result['checksum'] = {
            'received': f"0x{checksum:02X}",
            'calculated': f"0x{calculated_cs:02X}",
            'valid': checksum == calculated_cs
        }
        pos += 1
        
        # 9. 检查结束字符
        if pos >= len(data):
            raise ValueError(f"数据长度不足，缺少结束字符")
        elif data[pos] != 0x16:
            # 如果不是0x16，可能是校验码计算有误，但仍记录实际值
            result['end_char'] = f"0x{data[pos]:02X}"
            result['end_char_note'] = f"期望0x16，实际0x{data[pos]:02X}"
        else:
            result['end_char'] = f"0x{data[pos]:02X}"
        
    def _parse_control_field(self, control: int) -> Dict[str, Any]:
        """解析控制域"""
        return {
            'raw': f"0x{control:02X}",
            'binary': f"{control:08b}",
            'direction': "上行" if (control & 0x80) else "下行",
            'prm': (control >> 6) & 1,
            'fcb': (control >> 5) & 1,
            'fcv': (control >> 4) & 1,
            'function_code': control & 0x0F,
            'description': self._get_control_description(control)
        }
    
    def _get_control_description(self, control: int) -> str:
        """获取控制域描述"""
        direction = "上行" if (control & 0x80) else "下行"
        func_code = control & 0x0F
        
        func_names = {
            0: "复位",
            1: "复位确认",
            3: "传送数据",
            4: "传送数据确认", 
            8: "请求响应数据",
            9: "请求响应数据确认",
            10: "请求1级数据",
            11: "请求2级数据"
        }
        
        func_name = func_names.get(func_code, f"未知功能码({func_code})")
        return f"{direction} - {func_name}"
    
    def _parse_address_field(self, addr_bytes: bytes) -> Dict[str, Any]:
        """解析地址域"""
        if len(addr_bytes) != 5:
            raise ValueError(f"地址域长度错误: {len(addr_bytes)}, 期望: 5")
            
        # 地址域按小端序解析
        addr_value = struct.unpack('<I', addr_bytes[:4])[0]  # 取前4字节
        msb = addr_bytes[4]  # 最高字节
        
        return {
            'raw': [f"0x{b:02X}" for b in addr_bytes],
            'address_value': addr_value,
            'msb': f"0x{msb:02X}",
            'full_address': (msb << 32) | addr_value,
            'description': f"设备地址: {addr_value:08X}{msb:02X}"
        }
    
    def _parse_application_layer(self, app_data: bytes) -> Dict[str, Any]:
        """解析应用层数据"""
        if len(app_data) < 2:
            return {'error': '应用层数据长度不足'}
            
        pos = 0
        result = {}
        
        # 1. AFN (应用功能码)
        afn = app_data[pos]
        result['afn'] = {
            'raw': f"0x{afn:02X}",
            'value': afn,
            'name': self.AFN_NAMES.get(afn, f"未知AFN({afn:02X})")
        }
        pos += 1
        
        # 2. SEQ (帧序列域)
        seq = app_data[pos]
        result['seq'] = self._parse_seq_field(seq)
        pos += 1
        
        # 3. 解析数据单元
        remaining_data = app_data[pos:]
        if afn == 0x10:  # 数据转发
            result['data_units'] = self._parse_data_forward_units(remaining_data)
        elif afn == 0x01:  # 复位命令，但可能包含电能数据
            result['data_units'] = self._parse_data_forward_units(remaining_data)
        else:
            result['data_units'] = self._parse_generic_data_units(remaining_data)
            
        return result
    
    def _parse_seq_field(self, seq: int) -> Dict[str, Any]:
        """解析SEQ字段"""
        return {
            'raw': f"0x{seq:02X}",
            'binary': f"{seq:08b}",
            'tpv': (seq >> 7) & 1,  # 时间标签有效位
            'fir': (seq >> 6) & 1,  # 首帧标志
            'fin': (seq >> 5) & 1,  # 末帧标志  
            'con': (seq >> 4) & 1,  # 确认标志
            'seq_num': seq & 0x0F,  # 帧序号
            'description': self._get_seq_description(seq)
        }
    
    def _get_seq_description(self, seq: int) -> str:
        """获取SEQ描述"""
        tpv = (seq >> 7) & 1
        fir = (seq >> 6) & 1
        fin = (seq >> 5) & 1
        con = (seq >> 4) & 1
        seq_num = seq & 0x0F
        
        desc_parts = []
        if tpv: desc_parts.append("时间标签有效")
        if fir: desc_parts.append("首帧")
        if fin: desc_parts.append("末帧")
        if con: desc_parts.append("需要确认")
        desc_parts.append(f"序号:{seq_num}")
        
        return ", ".join(desc_parts)
    
    def _parse_data_forward_units(self, data: bytes) -> List[Dict[str, Any]]:
        """解析数据转发的数据单元 (AFN=10H)"""
        units = []
        pos = 0
        
        while pos < len(data):
            try:
                # 数据单元标识 (4字节)
                if pos + 4 > len(data):
                    # 如果剩余数据不足4字节，可能是其他格式的数据
                    units.append({
                        'remaining_data': [f"0x{b:02X}" for b in data[pos:]],
                        'description': f"剩余数据 ({len(data) - pos} 字节)"
                    })
                    break
                    
                unit_id_bytes = data[pos:pos+4]
                unit_id = struct.unpack('<I', unit_id_bytes)[0]
                
                # 解析数据单元标识的结构
                pn = (unit_id >> 16) & 0xFFFF  # 信息点号Pn (高16位)
                fn = unit_id & 0xFFFF          # 功能码Fn (低16位)
                
                unit = {
                    'unit_id': {
                        'raw': [f"0x{b:02X}" for b in unit_id_bytes],
                        'value': f"0x{unit_id:08X}",
                        'pn': pn,
                        'fn': fn,
                        'description': f"Pn={pn}, Fn={fn}"
                    }
                }
                pos += 4
                
                # 检查是否是F254 (主动上报)
                if fn == 0x00FE:  # F254
                    # 解析主动上报数据
                    remaining = data[pos:]
                    unit['data'] = self._parse_active_report_data(remaining)
                    pos = len(data)  # 主动上报数据占用剩余所有数据
                elif fn == 0x0000:  # F0，可能是其他类型的数据
                    # 解析F0数据（可能包含表计数据）
                    remaining = data[pos:]
                    unit['data'] = self._parse_f0_data(remaining)
                    pos = len(data)  # 简化处理，占用剩余所有数据
                else:
                    # 其他功能码的数据解析
                    remaining = data[pos:]
                    if remaining:
                        unit['data'] = self._parse_unit_data(remaining, unit_id)
                        pos = len(data)  # 简化处理
                    
                units.append(unit)
                
            except Exception as e:
                units.append({
                    'error': f"解析数据单元时出错: {str(e)}",
                    'remaining_data': [f"0x{b:02X}" for b in data[pos:]]
                })
                break
                
        return units
    
    def _parse_generic_data_units(self, data: bytes) -> List[Dict[str, Any]]:
        """解析通用数据单元"""
        # 简化处理，直接返回原始数据
        return [{
            'raw_data': [f"0x{b:02X}" for b in data],
            'description': "通用数据单元（未详细解析）"
        }]
    
    def _parse_active_report_data(self, data: bytes) -> Dict[str, Any]:
        """解析主动上报数据 (F254)"""
        result = {
            'data_format': 'AFN10H_F254_主动上报',
            'raw_length': len(data),
            'raw_data': [f"0x{b:02X}" for b in data]
        }
        
        if len(data) < 8:
            result['error'] = '主动上报数据长度不足'
            return result
            
        pos = 0
        
        try:
            # 解析模块维测数据部分
            module_data_length = 8  # 通常前8字节是模块维测数据
            if len(data) >= module_data_length:
                module_data = data[pos:pos+module_data_length]
                result['module_maintenance'] = self._parse_module_maintenance_data(module_data)
                pos += module_data_length
            
            # 解析TAG数据部分
            remaining_data = data[pos:]
            if remaining_data:
                result['tag_data'] = self._parse_tag_data(remaining_data)
                
        except Exception as e:
            result['parse_error'] = str(e)
            
        return result
    
    def _parse_module_maintenance_data(self, data: bytes) -> Dict[str, Any]:
        """解析模块维测数据"""
        if len(data) != 8:
            return {'error': f'模块维测数据长度错误: {len(data)}, 期望: 8'}
            
        return {
            'raw': [f"0x{b:02X}" for b in data],
            'description': '模块维测数据',
            'csq': data[0] if len(data) > 0 else 0,
            'rsrp': data[1] if len(data) > 1 else 0,
            'snr': data[2] if len(data) > 2 else 0,
            'ecl': data[3] if len(data) > 3 else 0,
            'vbat': data[4] if len(data) > 4 else 0,
            'bat_cap': data[5] if len(data) > 5 else 0,
            'reserved': [f"0x{b:02X}" for b in data[6:8]]
        }
    
    def _parse_tag_data(self, data: bytes) -> Dict[str, Any]:
        """解析TAG数据"""
        result = {
            'raw': [f"0x{b:02X}" for b in data],
            'length': len(data),
            'tags': []
        }
        
        pos = 0
        
        # 检查是否有FD标识符
        if pos < len(data) and data[pos] == 0xFD:
            result['format_identifier'] = f"0x{data[pos]:02X}"
            pos += 1
            
            # 解析后续的长度字段 (2字节，大端序)
            if pos + 2 <= len(data):
                tag_length = struct.unpack('>H', data[pos:pos+2])[0]  # 改为大端序
                result['tag_section_length'] = tag_length
                result['declared_length'] = tag_length
                pos += 2
                
                # 使用实际剩余数据长度
                actual_length = len(data) - pos
                result['actual_length'] = actual_length
                
                # 解析TAG数据项
                tag_data = data[pos:pos+min(tag_length, actual_length)]
                result['tags'] = self._parse_individual_tags(tag_data)
        else:
            # 没有FD标识符，直接解析TAG
            result['tags'] = self._parse_individual_tags(data)
            
        return result
    
    def _parse_individual_tags(self, data: bytes) -> List[Dict[str, Any]]:
        """解析单个TAG数据项"""
        tags = []
        pos = 0
        
        while pos < len(data):
            try:
                # 每个TAG项的结构：TAG(2字节) + 数据长度 + 数据内容
                if pos + 2 > len(data):
                    break
                    
                tag_id = struct.unpack('<H', data[pos:pos+2])[0]
                pos += 2
                
                # 根据TAG类型确定数据长度
                tag_info = self._get_tag_info(tag_id)
                data_length = tag_info.get('length', 4)  # 默认4字节
                
                if pos + data_length > len(data):
                    data_length = len(data) - pos  # 使用剩余数据长度
                
                tag_data = data[pos:pos+data_length] if data_length > 0 else b''
                pos += data_length
                
                tag_item = {
                    'tag_id': f"0x{tag_id:04X}",
                    'tag_name': tag_info.get('name', f'未知TAG({tag_id:04X})'),
                    'data_length': data_length,
                    'raw_data': [f"0x{b:02X}" for b in tag_data],
                    'parsed_value': self._parse_tag_value(tag_id, tag_data)
                }
                
                tags.append(tag_item)
                
            except Exception as e:
                tags.append({
                    'error': f'解析TAG时出错: {str(e)}',
                    'remaining_data': [f"0x{b:02X}" for b in data[pos:]]
                })
                break
                
        return tags
    
    def _get_tag_info(self, tag_id: int) -> Dict[str, Any]:
        """获取TAG信息"""
        tag_definitions = {
            # 基础信息
            0x0001: {'name': '表号', 'length': 10},
            0x0002: {'name': '时间', 'length': 7}, 
            
            # 电压相关
            0x0014: {'name': 'A相电压', 'length': 4},
            0x0015: {'name': 'B相电压', 'length': 4},
            0x0016: {'name': 'C相电压', 'length': 4},
            
            # 电流相关
            0x0017: {'name': 'A相电流', 'length': 4},
            0x0018: {'name': 'B相电流', 'length': 4},
            0x0019: {'name': 'C相电流', 'length': 4},
            
            # 电能相关（根据文档更正）
            0x0027: {'name': '（当前）组合有功总电能', 'length': 4},
            0x0028: {'name': '（当前）组合有功费率1电能', 'length': 4},
            0x0029: {'name': '（当前）组合有功费率2电能', 'length': 4},
            0x002A: {'name': '（当前）组合有功费率3电能', 'length': 4},
            0x002B: {'name': '（当前）组合有功费率4电能', 'length': 4},
            
            # 电能相关 - 扩展更多可能的TAG
            0x0049: {'name': '正向有功总电能', 'length': 4},
            0x004A: {'name': '反向有功总电能', 'length': 4},
            0x0059: {'name': '组合有功1总电能', 'length': 4},
            0x005A: {'name': '组合有功2总电能', 'length': 4},
            0x005B: {'name': '组合有功3总电能', 'length': 4},
            0x005C: {'name': '组合有功4总电能', 'length': 4},
            
            # 费率电能
            0x0061: {'name': '正向有功费率1电能', 'length': 4},
            0x0062: {'name': '正向有功费率2电能', 'length': 4},
            0x0063: {'name': '正向有功费率3电能', 'length': 4},
            0x0064: {'name': '正向有功费率4电能', 'length': 4},
            
            # 无功电能
            0x0081: {'name': '正向无功总电能', 'length': 4},
            0x0082: {'name': '反向无功总电能', 'length': 4},
        }
        
        return tag_definitions.get(tag_id, {'name': f'未知TAG({tag_id:04X})', 'length': 4})
    
    def _parse_tag_value(self, tag_id: int, data: bytes) -> Any:
        """解析TAG数据值"""
        if len(data) == 0:
            return None
            
        try:
            # 根据TAG类型解析数据
            if tag_id == 0x0001:  # 表号
                return ''.join([f"{b:02X}" for b in data])
            elif tag_id == 0x0002:  # 时间
                if len(data) >= 6:
                    return f"20{data[0]:02X}-{data[1]:02X}-{data[2]:02X} {data[4]:02X}:{data[5]:02X}:{data[6]:02X}" if len(data) > 6 else f"20{data[0]:02X}-{data[1]:02X}-{data[2]:02X}"
            elif tag_id == 0x0014:  # 电表运行状态字3 (2字节)
                if len(data) >= 2:
                    value = struct.unpack('>H', data[:2])[0]
                    return f"0x{value:04X}"
            elif tag_id == 0x0015:  # A相电压 (2字节BCD, 单位0.1V)
                if len(data) >= 2:
                    bcd_str = ""
                    for b in data[:2]:
                        bcd_str += f"{(b>>4)&0x0F}{b&0x0F}"
                    value = int(bcd_str) / 10
                    return f"{value:.1f}V"
            elif tag_id == 0x0018:  # A相电流 (3字节BCD, 单位0.001A)  
                if len(data) >= 3:
                    bcd_str = ""
                    for b in data[:3]:
                        bcd_str += f"{(b>>4)&0x0F}{b&0x0F}"
                    value = int(bcd_str) / 1000
                    return f"{value:.3f}A"
            elif tag_id in [0x001B, 0x001C]:  # 功率类 (3字节BCD, 单位0.001kW)
                if len(data) >= 3:
                    bcd_str = ""
                    for b in data[:3]:
                        bcd_str += f"{(b>>4)&0x0F}{b&0x0F}"
                    value = int(bcd_str) / 1000
                    return f"{value:.3f}kW"
            elif tag_id in [0x001F, 0x0020]:  # 视在功率 (3字节BCD, 单位0.001kVA)
                if len(data) >= 3:
                    bcd_str = ""
                    for b in data[:3]:
                        bcd_str += f"{(b>>4)&0x0F}{b&0x0F}"
                    value = int(bcd_str) / 1000
                    return f"{value:.3f}kVA"
            elif tag_id in [0x0023, 0x0024]:  # 功率因数 (2字节BCD, 单位0.001)
                if len(data) >= 2:
                    bcd_str = ""
                    for b in data[:2]:
                        bcd_str += f"{(b>>4)&0x0F}{b&0x0F}"
                    value = int(bcd_str) / 1000
                    return f"{value:.3f}"
            elif tag_id in [0x0027, 0x0028, 0x0029, 0x002A, 0x002B]:  # 电能类（BCD码格式）
                if len(data) >= 4:
                    # BCD码解析：每个字节的高4位和低4位分别表示两个十进制数字
                    bcd_str = ""
                    for byte in data[:4]:  # 按正常字节序，不反转
                        high_digit = (byte >> 4) & 0x0F
                        low_digit = byte & 0x0F
                        bcd_str += f"{high_digit}{low_digit}"
                    
                    try:
                        # 去掉前导零（根据文档示例修正）
                        trimmed_bcd = bcd_str.lstrip('0')
                        if not trimmed_bcd:
                            trimmed_bcd = '0'
                        
                        # 电能数据固定2位小数（根据文档示例：00031224 -> 312.24）
                        if len(trimmed_bcd) >= 2:
                            integer_part = trimmed_bcd[:-2] if len(trimmed_bcd) > 2 else '0'
                            decimal_part = trimmed_bcd[-2:]
                            if not integer_part:
                                integer_part = '0'
                            value = float(f"{integer_part}.{decimal_part}")
                        else:
                            value = float(trimmed_bcd) / 100
                        
                        return f"{value:.2f} kWh"
                    except:
                        return f"BCD解析错误: {data.hex().upper()}"
            elif tag_id in [0x0049, 0x004A, 0x004E, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030]:  # 无功电能和正向有功电能类（BCD码）
                if len(data) >= 4:
                    # BCD码解析
                    bcd_str = ""
                    for byte in data[:4]:
                        bcd_str += f"{(byte>>4)&0x0F}{byte&0x0F}"
                    
                    try:
                        trimmed_bcd = bcd_str.lstrip('0') or '0'
                        if len(trimmed_bcd) >= 2:
                            integer_part = trimmed_bcd[:-2] if len(trimmed_bcd) > 2 else '0'
                            decimal_part = trimmed_bcd[-2:]
                            if not integer_part:
                                integer_part = '0'
                            return f"{integer_part}.{decimal_part}kWh"
                        else:
                            return f"0.{trimmed_bcd.zfill(2)}kWh"
                    except:
                        return f"BCD解析错误: {data.hex().upper()}"
            else:
                # 默认按整数解析
                if len(data) == 4:
                    return struct.unpack('<I', data)[0]
                elif len(data) == 2:
                    return struct.unpack('<H', data)[0]
                else:
                    return ''.join([f"{b:02X}" for b in data])
                    
        except Exception as e:
            return f"解析错误: {str(e)}"
        
        return ''.join([f"{b:02X}" for b in data])
    
    def _parse_f0_data(self, data: bytes) -> Dict[str, Any]:
        """解析F0功能码数据"""
        result = {
            'data_format': 'AFN10H_F0_数据',
            'raw_length': len(data),
            'raw_data': [f"0x{b:02X}" for b in data[:32]]  # 只显示前32字节
        }
        
        if len(data) < 8:
            result['error'] = 'F0数据长度不足'
            return result
            
        pos = 0
        
        try:
            # 方法1：查找TAG 0x0001的位置来定位TAG数据起始点
            tag_0001_pos = -1
            for i in range(min(30, len(data) - 15)):  # 在前30字节内查找
                if data[i:i+2] == b'\x00\x01' and i + 8 <= len(data):
                    # 验证：检查后面8字节是否可能是TAG 0x0002（时间）
                    # TAG结构：00 01 + 6字节表号 + 00 02 + ...
                    if i + 10 <= len(data) and data[i+8:i+10] == b'\x00\x02':
                        tag_0001_pos = i
                        break
            
            if tag_0001_pos >= 0:
                # 找到TAG数据起始点
                result['tag_start_position'] = tag_0001_pos
                result['header_data'] = [f"0x{b:02X}" for b in data[:tag_0001_pos]]
                
                # 解析TAG数据
                tag_data = data[tag_0001_pos:]
                result['tag_data_direct'] = self._parse_direct_tag_data(tag_data)
            
            # 方法2：检查第一个字节，判断数据格式
            elif data[0] <= 0x1F:  # 端口号范围1-31
                # AFN10H F1透传格式：端口(1) + 模块维测(8) + 协议类型(1) + 长度(2) + 数据
                result['port'] = data[0]
                pos = 1
                
                if len(data) >= 12:
                    module_data = data[pos:pos+8]
                    result['module_maintenance'] = {
                        'raw': [f"0x{b:02X}" for b in module_data],
                        'csq': module_data[0] if module_data[0] != 0xFF else None,
                    }
                    pos += 8
                    
                    result['protocol_type'] = data[pos]
                    pos += 1
                    
                    data_len = struct.unpack('>H', data[pos:pos+2])[0]
                    result['declared_data_length'] = data_len
                    pos += 2
                    
                    # 剩余数据就是TAG数据
                    remaining_data = data[pos:]
                    if remaining_data:
                        # 直接解析TAG数据（不需要FD标识）
                        result['tag_data_direct'] = self._parse_direct_tag_data(remaining_data)
            else:
                # 原来的解析逻辑
                # 解析前8字节作为模块维测数据
                if len(data) >= 8:
                    module_data = data[pos:pos+8]
                    result['module_maintenance'] = {
                        'raw': [f"0x{b:02X}" for b in module_data],
                        'description': '模块维测数据',
                    }
                    pos += 8
                
                # 解析剩余数据
                remaining_data = data[pos:]
                if remaining_data:
                    # 检查是否有FD标识符开始的TAG数据
                    if len(remaining_data) >= 3 and remaining_data[0] == 0x00 and remaining_data[1] == 0x38 and remaining_data[2] == 0x00:
                        # 跳过这3个字节
                        pos += 3
                        remaining_data = data[pos:]
                        
                    if len(remaining_data) >= 1 and remaining_data[0] == 0xFD:
                        # 这是TAG数据格式
                        result['tag_data'] = self._parse_tag_data(remaining_data)
                    else:
                        # 其他格式数据
                        result['other_data'] = {
                            'raw': [f"0x{b:02X}" for b in remaining_data],
                            'length': len(remaining_data),
                            'description': '其他数据内容'
                        }
                
        except Exception as e:
            result['parse_error'] = str(e)
            
        return result

    def _parse_direct_tag_data(self, data: bytes) -> Dict[str, Any]:
        """解析直接TAG数据（不带FD标识）"""
        result = {
            'format': 'Direct TAG Format',
            'tags': []
        }
        
        pos = 0
        tag_names = {
            0x0001: ('表号', 6),
            0x0002: ('时间', 7),
            0x0006: ('上1次日冻结时间', 5),
            0x0007: ('上1次日冻结正向有功电能数据', 20),
            0x0008: ('上1次日冻结反向有功电能数据', 20),
            0x0014: ('电表运行状态字3', 2),
            0x0015: ('A相电压', 2),
            0x0018: ('A相电流', 3),
            0x001B: ('瞬时总有功功率', 3),
            0x001C: ('瞬时A相有功功率', 3),
            0x001F: ('瞬时总视在功率', 3),
            0x0020: ('瞬时A相视在功率', 3),
            0x0023: ('总功率因数', 2),
            0x0024: ('A相功率因数', 2),
            0x0027: ('（当前）组合有功总电能', 4),
            0x0028: ('（当前）组合有功费率1电能', 4),
            0x0029: ('（当前）组合有功费率2电能', 4),
            0x002A: ('（当前）组合有功费率3电能', 4),
            0x002B: ('（当前）组合有功费率4电能', 4),
            0x0049: ('（当前）组合无功1总电能', 4),
            0x004E: ('（当前）组合无功2总电能', 4),
        }
        
        while pos + 2 <= len(data):
            try:
                # 读取TAG（大端序）
                tag_id = struct.unpack('>H', data[pos:pos+2])[0]
                pos += 2
                
                if tag_id in tag_names:
                    tag_name, data_len = tag_names[tag_id]
                    
                    if pos + data_len <= len(data):
                        tag_data = data[pos:pos+data_len]
                        pos += data_len
                        
                        # 解析TAG值
                        parsed_value = self._parse_tag_value(tag_id, tag_data)
                        
                        result['tags'].append({
                            'tag_id': f"0x{tag_id:04X}",
                            'tag_name': tag_name,
                            'raw_data': [f"0x{b:02X}" for b in tag_data],
                            'parsed_value': parsed_value
                        })
                    else:
                        break
                else:
                    # 未知TAG，停止解析
                    break
            except:
                break
        
        return result
    
    def _parse_unit_data(self, data: bytes, unit_id: int) -> Dict[str, Any]:
        """解析单元数据内容"""
        # 这里可以根据不同的功能码和数据标识进行详细解析
        return {
            'raw': [f"0x{b:02X}" for b in data[:min(32, len(data))]],  # 只显示前32字节
            'length': len(data),
            'description': "数据内容（简化显示）"
        }
    
    def _calculate_checksum(self, data: bytes) -> int:
        """计算校验和"""
        return sum(data) & 0xFF


def parse_3761_message(message: str) -> Dict[str, Any]:
    """
    解析3761协议报文的主函数
    
    Args:
        message: 十六进制格式的报文字符串
        
    Returns:
        解析结果字典
    """
    parser = Frame3761Parser()
    return parser.parse_frame(message)


def format_3761_result(result: Dict[str, Any]) -> str:
    """
    格式化3761解析结果为可读字符串（参考main.py的格式）
    
    Args:
        result: 解析结果字典
        
    Returns:
        格式化的字符串
    """
    lines = []
    lines.append("=" * 60)
    lines.append("3761协议报文解析结果")
    lines.append("=" * 60)
    
    # 帧头信息
    lines.append("\n【帧头信息】")
    lines.append(f"起始符: {result.get('start_char', 'N/A')} ({'有效' if result.get('start_char') == '0x68' else '无效'})")
    
    length_info = result.get('length_field', {})
    lines.append(f"长度域: {length_info.get('declared_length', 0)} 字节 (实际: {length_info.get('actual_frame_length', 0)} 字节)")
    
    control_info = result.get('control_field', {})
    lines.append(f"控制域: {control_info.get('raw', 'N/A')} ({control_info.get('description', '未知')})")
    
    address_info = result.get('address_field', {})
    lines.append(f"设备地址: {address_info.get('description', '未知')}")
    
    # 应用层信息
    app_data = result.get('application_data', {})
    if app_data:
        lines.append(f"\n【应用层信息】")
        
        afn_info = app_data.get('afn', {})
        lines.append(f"应用功能: {afn_info.get('name', '未知')} ({afn_info.get('raw', 'N/A')})")
        
        seq_info = app_data.get('seq', {})
        lines.append(f"帧序列: {seq_info.get('description', '未知')}")
        
        # 数据单元信息
        data_units = app_data.get('data_units', [])
        if data_units:
            lines.append(f"\n【数据单元信息】")
            for i, unit in enumerate(data_units):
                if 'unit_id' in unit:
                    unit_id = unit['unit_id']
                    lines.append(f"数据单元{i+1}: Pn={unit_id.get('pn', 0)}, Fn={unit_id.get('fn', 0)}")
                    
                    # 解析数据内容
                    if 'data' in unit:
                        data_info = unit['data']
                        data_format = data_info.get('data_format', '')
                        
                        if data_format == 'AFN10H_F254_主动上报':
                            # 显示主动上报的TAG数据
                            tag_data = data_info.get('tag_data', {})
                            tags = tag_data.get('tags', [])
                            if tags:
                                lines.append(f"\n【电表数据】")
                                for tag in tags:
                                    if 'tag_name' in tag and 'parsed_value' in tag:
                                        lines.append(f"{tag['tag_name']}: {tag['parsed_value']}")
                                        
                        elif data_format == 'AFN10H_F0_数据':
                            # 检查是否有TAG数据
                            tag_data = data_info.get('tag_data', {})
                            tag_data_direct = data_info.get('tag_data_direct', {})
                            other_data = data_info.get('other_data', {})
                            
                            # 优先显示直接TAG数据
                            if tag_data_direct and 'tags' in tag_data_direct and tag_data_direct['tags']:
                                tags = tag_data_direct['tags']
                                lines.append(f"\n【电表数据】")
                                for tag in tags:
                                    if 'tag_name' in tag and 'parsed_value' in tag:
                                        # 特别标注电能数据
                                        if '电能' in tag['tag_name']:
                                            lines.append(f"{tag['tag_name']}: {tag['parsed_value']} ⭐")
                                        else:
                                            lines.append(f"{tag['tag_name']}: {tag['parsed_value']}")
                            # 如果有TAG数据就显示TAG数据
                            elif tag_data and 'tags' in tag_data and tag_data['tags']:
                                tags = tag_data['tags']
                                lines.append(f"\n【电表数据】")
                                for tag in tags:
                                    if 'tag_name' in tag and 'parsed_value' in tag:
                                        # 特别标注电能数据
                                        if '电能' in tag['tag_name']:
                                            lines.append(f"{tag['tag_name']}: {tag['parsed_value']} ⭐")
                                        else:
                                            lines.append(f"{tag['tag_name']}: {tag['parsed_value']}")
                            # 如果没有TAG数据，但有其他数据，尝试解析为FD格式TAG数据
                            elif other_data and other_data.get('length', 0) > 0:
                                lines.append(f"\n【电表数据】")
                                # 从other_data中解析FD格式的TAG数据
                                raw_data = other_data.get('raw', [])
                                if len(raw_data) > 0:
                                    # 将原始数据转换为字节
                                    hex_str = ''.join([x.replace('0x', '').replace('0X', '') for x in raw_data])
                                    try:
                                        raw_bytes = bytes.fromhex(hex_str)
                                        
                                        # 查找FD标识的位置
                                        fd_pos = raw_bytes.find(b'\xFD')
                                        
                                        # 检查是否找到FD标识
                                        if fd_pos >= 0 and fd_pos + 7 < len(raw_bytes):
                                            # FD格式：0xFD + 长度(2字节) + 控制字(2字节) + 时间控制字(2字节) + 数据
                                            tag_length = struct.unpack('>H', raw_bytes[fd_pos+1:fd_pos+3])[0]
                                            # 跳过：FD(1) + 长度(2) + 控制字(2) + 时间控制字(2) = 7字节
                                            data_start = fd_pos + 7
                                            
                                            # 第一个字节是TAG数量
                                            if data_start < len(raw_bytes):
                                                tag_count = raw_bytes[data_start]
                                                pos = data_start + 1
                                                
                                                # TAG定义（大端序）- 根据报文实际格式修正
                                                tag_names = {
                                                    0x0001: ('表号', 6),  # 6字节BCD码
                                                    0x0002: ('时间', 7),  # 7字节时间
                                                    0x0027: ('（当前）组合有功总电能', 4),
                                                    0x0028: ('（当前）组合有功费率1电能', 4),
                                                    0x0029: ('（当前）组合有功费率2电能', 4),
                                                    0x002A: ('（当前）组合有功费率3电能', 4),
                                                    0x002B: ('（当前）组合有功费率4电能', 4),
                                                    0x002C: ('（当前）正向有功总电能', 4),
                                                    0x0049: ('（当前）组合无功1总电能', 4),
                                                    0x004E: ('（当前）组合无功2总电能', 4),
                                                }
                                                
                                                found_energy = False
                                                # 逐个解析TAG
                                                while pos + 2 <= len(raw_bytes):
                                                    # 读取TAG（大端序，2字节）
                                                    tag_id = struct.unpack('>H', raw_bytes[pos:pos+2])[0]
                                                    pos += 2
                                                    
                                                    if tag_id in tag_names:
                                                        tag_name, data_len = tag_names[tag_id]
                                                        
                                                        if pos + data_len <= len(raw_bytes):
                                                            tag_data_bytes = raw_bytes[pos:pos+data_len]
                                                            pos += data_len
                                                            
                                                            # 解析电能数据（BCD码）
                                                            if tag_id >= 0x0027 and tag_id <= 0x004E and data_len == 4:
                                                                bcd_str = ""
                                                                for byte in tag_data_bytes:
                                                                    high_digit = (byte >> 4) & 0x0F
                                                                    low_digit = byte & 0x0F
                                                                    bcd_str += f"{high_digit}{low_digit}"
                                                                
                                                                # 去掉前导零
                                                                trimmed_bcd = bcd_str.lstrip('0')
                                                                if not trimmed_bcd:
                                                                    trimmed_bcd = '0'
                                                                
                                                                # 电能数据固定2位小数
                                                                if len(trimmed_bcd) >= 2:
                                                                    integer_part = trimmed_bcd[:-2] if len(trimmed_bcd) > 2 else '0'
                                                                    decimal_part = trimmed_bcd[-2:]
                                                                    if not integer_part:
                                                                        integer_part = '0'
                                                                    energy_value = float(f"{integer_part}.{decimal_part}")
                                                                else:
                                                                    energy_value = float(trimmed_bcd) / 100
                                                                
                                                                symbol = " ⭐" if "总电能" in tag_name else ""
                                                                lines.append(f"{tag_name}: {energy_value:.2f} kWh{symbol}")
                                                                found_energy = True
                                                    else:
                                                        # 未知TAG，跳过
                                                        break
                                                
                                                if not found_energy:
                                                    lines.append("⚠️ 未找到有效电能数据")
                                        else:
                                            lines.append("⚠️ 数据格式不是标准FD格式")
                                    except Exception as e:
                                        lines.append(f"数据解析错误: {str(e)}")
    
    # 校验信息
    checksum_info = result.get('checksum', {})
    lines.append(f"\n【校验信息】")
    lines.append(f"校验码: {checksum_info.get('received', 'N/A')} ({'有效' if checksum_info.get('valid') else '无效'})")
    lines.append(f"结束符: {result.get('end_char', 'N/A')} ({'有效' if result.get('end_char') == '0x16' else '无效'})")
    
    lines.append("=" * 60)
    
    return "\n".join(lines)


# 测试函数
def test_parser():
    """测试解析器"""
    # 用户提供的测试报文
    test_message = "68 42 01 42 01 68 CA 05 06 33 A0 01 10 75 00 00 20 1F 00 1A 00 00 00 01 00 00 FF 00 38 00 FD 00 34 00 00 00 00 07 00 01 69 35 06 05 00 51 00 02 25 09 30 02 09 58 00 00 27 00 03 67 50 00 28 00 03 67 50 00 29 00 00 00 00 00 2A 00 00 00 00 00 2B 00 00 00 00 37 2D 16"
    
    print("=" * 60)
    print("3761协议报文解析测试")
    print("=" * 60)
    print(f"原始报文: {test_message}")
    print("=" * 60)
    
    result = parse_3761_message(test_message)
    
    # 打印简洁的格式化结果（参考main.py的风格）
    if result.get('parse_success'):
        print(format_3761_result(result))
    else:
        print(f"❌ 解析失败: {result.get('error', '未知错误')}")
    
    return result


if __name__ == "__main__":
    test_parser()
